﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using ControleRepresentante.Logic;
using ControleRepresentante.Logic.Models;
using ControleRepresentante.Logic.Repositories;
using ControleRepresentante.Logic.Statistics;
using WebSite.Controllers.ControllerExtensions;
using WebSite.ViewModels.DetailsViewModels;
using WebSite.ViewModels.EditViewModels;
using WebSite.ViewModels.IndexViewModels;
using Attribute = ControleRepresentante.Logic.Models.Attribute;

namespace WebSite.Controllers
{
    public abstract class AttributeHolderControllerBase<TRepository, TModel, TStatistics> : CRUDControllerBase<TRepository, TModel, TStatistics>
        where TRepository : class, IAttributeHolderRepository<TModel, TStatistics>
        where TModel : AttributeHolder 
        where TStatistics : IStatistics
    {
        private IEnumerable<Attribute> m_Attributes;

        private IEnumerable<Attribute> Attributes
        {
            get
            {
                if (m_Attributes == null)
                {
                    IAttributeRepository attributeRepository = RepositoryProvider.GetRepository<IAttributeRepository>();
                    m_Attributes = attributeRepository.GetAttributesByType(AttributeType);
                }
                return m_Attributes;
            }
        }

        protected AttributeHolderControllerBase(IRepositoryProvider repositoryProvider, ISessionConfiguration sessionConfiguration, IControllerExtensionProvider controllerExtensionProvider, params object[] repositoryParameters)
            : base(repositoryProvider, sessionConfiguration, controllerExtensionProvider, repositoryParameters)
        {
        }

        protected sealed override IIndexViewModel GetIndexViewModel(TStatistics statistics)
        {
            IEnumerable<AttributeItem> attributeNames = Attributes.Select(x => new AttributeItem(x));
            IAttributeHolderIndexViewModel attributeHolderIndexViewModel = GetAttributeHolderIndexViewModel(statistics);
            attributeHolderIndexViewModel.Attributes = attributeNames;
            return attributeHolderIndexViewModel;
        }

        protected override void RegisterIndexColumns(IIndexColumnsProvider indexColumnsProvider)
        {
            base.RegisterIndexColumns(indexColumnsProvider);
            foreach (Attribute attribute in Attributes)
            {
                indexColumnsProvider.RegisterColumn(attribute);
            }
        }

        protected void SetAttributeSearchValues(IAttributeHolderIndexViewModel attributeHolderIndexViewModel, Dictionary<Attribute, string> attributeMap)
        {
            foreach (AttributeItem attributeItem in attributeHolderIndexViewModel.Attributes)
            {
                string value;
                if (attributeMap.TryGetValue(attributeItem.Attribute, out value))
                {
                    attributeItem.Value = value;
                }
            }
        }

        protected override DetailsViewModel GetDetailsViewModel(TModel model)
        {
            AttributeHolderDetailsViewModel attributeHolderDetailsViewModel = GetAttributeHolderDetailsViewModel(model);
            attributeHolderDetailsViewModel.Attributes = GetAttributes(model);
            return attributeHolderDetailsViewModel;
        }

        protected sealed override EditViewModel GetEditViewModel(TModel model, bool isNew)
        {
            AttributeHolderEditViewModel attributeHolderEditViewModel = GetEditViewModel();
            attributeHolderEditViewModel.Attributes = GetAttributes(model);
            return attributeHolderEditViewModel;
        }

        protected abstract AttributeHolderDetailsViewModel GetAttributeHolderDetailsViewModel(TModel model);
        protected abstract AttributeHolderEditViewModel GetEditViewModel();
        protected abstract IAttributeHolderIndexViewModel GetAttributeHolderIndexViewModel(TStatistics statistics);

        protected override TModel CreateInstance()
        {
            TModel model = base.CreateInstance();
            model.Representante = Repository.GetRepresentante();
            return model;
        }

        #region Attributes

        protected abstract AttributeType AttributeType { get; }

        private Dictionary<string, string> GetAttributes(TModel model)
        {
            IAttributeRepository attributeRepository = RepositoryProvider.GetRepository<IAttributeRepository>();
            StatisticsBase statistics;
            return attributeRepository.GetModels(out statistics)
                .Where(x => x.Type == AttributeType)
                .ToDictionary(
                    x => "_" + x.Name.Replace(' ', '_'),
                    x =>
                        {
                            AttributeValue attributeValue = model.AttributeValues.FirstOrDefault(y => y.Attribute.Id == x.Id);
                            return attributeValue == null ? String.Empty : attributeValue.Value;
                        });
        }

        protected void UpdateAttributesToModel(FormCollection formCollection)
        {
            IAttributeRepository attributeRepository = RepositoryProvider.GetRepository<IAttributeRepository>();
            StatisticsBase statistics;
            IEnumerable<Attribute> attributes = attributeRepository.GetModels(out statistics);
            Dictionary<string, string> attributeMap = GetAttributesFromFormCollection(formCollection);
            foreach (KeyValuePair<string, string> keyValuePair in attributeMap)
            {
                Attribute attribute = attributes.First(x => x.Name == keyValuePair.Key);
                AttributeValue attributeValue = Model.AttributeValues.FirstOrDefault(x => x.Attribute == attribute);
                if (attributeValue == null)
                {
                    attributeValue = new AttributeValue { Attribute = attribute };
                    Model.AddAttributeValue(attributeValue);
                }
                attributeValue.Value = keyValuePair.Value;
            }
        }

        protected Dictionary<Attribute, string> GetAttributeMap(IAttributeRepository attributeRepository, FormCollection formCollection)
        {
            StatisticsBase statistics;
            IEnumerable<Attribute> attributes = attributeRepository.GetModels(out statistics);
            return GetAttributesFromFormCollection(formCollection)
                .ToDictionary(
                    x => attributes.First(y => y.Name == x.Key),
                    x => x.Value.ToLower());
        }

        private static Dictionary<string, string> GetAttributesFromFormCollection(FormCollection formCollection)
        {
            if (formCollection == null)
            {
                return new Dictionary<string, string>();
            }

            return formCollection.AllKeys
                .Where(x => x.StartsWith("_") && !String.IsNullOrEmpty(formCollection[x]))
                .ToDictionary(
                    key => key.Substring(1).Replace('_', ' '),
                    key => formCollection[key]);
        }

        #endregion

        [HttpPost]
        public ActionResult SearchAttribute(Guid id, string text)
        {
            return new JsonResult { Data = Repository.SearchAttribute(id, text, AttributeType) };
        }
    }
}